#pragma once

#include "Core/Macros.h"
#include "Core/Math/Math.h"
#include "Camera.h"
#include "Core/Math/Quaternion.h"

namespace SL
{

struct MouseEvent;
struct KeyboardEvent;
struct GamepadState;

class SELAH_API CameraController
{
public:
    CameraController(Camera* pCamera);
    ~CameraController() = default;

    /** Handle mouse events
     */
    virtual bool onMouseEvent(const MouseEvent& mouseEvent) { return false; }

    /** Handle keyboard events
     */
    virtual bool onKeyEvent(const KeyboardEvent& keyboardEvent) { return false; }

    /** Handle gamepad state.
     */
    virtual bool onGamepadState(const GamepadState& gamepadState) { return false; }

    /** Update the camera position and orientation.
        \return Whether the camera was updated/changed
    */
    virtual bool update(float dt) = 0;

    float* getSensitivity() { return &sensitivity; }

protected:
    Camera* pCamera = nullptr;
    float sensitivity = 3.f;
};

class SELAH_API OrbiterCameraController : public CameraController
{
public:
    OrbiterCameraController(Camera* pCamera) : CameraController(pCamera) {}

    /** Handle mouse events
     */
    bool onMouseEvent(const MouseEvent& mouseEvent) override;

    /** Set the model parameters
        \param[in] Center The model's center. This is the position in which the camera will orbit around.
        \param[in] Radius The model's radius. Used to determin the speed of movement when zooming in/out.
        \param[in] InitialDistanceInRadius The initial distance of the camera from the model, measured in the model's radius.
    */
    void setModelParams(const float3& center, float radius, float initialDistanceInRadius);

    /** Update the camera position and orientation.
        \return Whether the camera was updated/changed
    */
    bool update(float dt) override;

    // /** Reset the mouse state to release all mouse buttons.
    //  */
    // void resetInputState() override;

private:
    float3 orbitCenter = float3(0, 0, 0);
    float orbitRadius = 5.0f;
    float zoomRadius = 1.0f;
    bool bDirty;

    float2 lastPos;
    float2 accDelta = float2(0,0);
    Quaternion accRotQuat = Quaternion::Identity();

    bool isRotating = false;

    void updateRotation(float dt);
};

} // namespace SL